home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / GopherTools / securegopher / telnet / telnetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-31  |  25.8 KB  |  1,287 lines

  1. /*
  2.  * 5799-WZQ (C) COPYRIGHT = NONE
  3.  * LICENSED MATERIALS - PROPERTY OF IBM
  4.  */
  5. /* $Header:telnetd.c 12.0$ */
  6. /* $ACIS:telnetd.c 12.0$ */
  7. /* $Source: /ibm/acis/usr/src/etc/RCS/telnetd.c,v $ */
  8.  
  9. #ifndef lint
  10. static char *rcsid = "$Header:telnetd.c 12.0$";
  11. #endif
  12.  
  13. #include <sys/nfs_defines.h>
  14.  
  15. /*
  16.  * Copyright (c) 1983,1986 Regents of the University of California.
  17.  * All rights reserved.  The Berkeley software License Agreement
  18.  * specifies the terms and conditions for redistribution.
  19.  */
  20.  
  21. #ifndef lint
  22. char copyright[] =
  23. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  24.  All rights reserved.\n";
  25. #endif not lint
  26.  
  27. #ifndef lint
  28. static char sccsid[] = "@(#)telnetd.c    5.20 (Berkeley) 9/2/87";
  29. #endif not lint
  30.  
  31. /*
  32.  * Telnet server.
  33.  */
  34. #include <sys/param.h>
  35. #include <sys/socket.h>
  36. #include <sys/wait.h>
  37. #include <sys/file.h>
  38. #include <sys/stat.h>
  39. #include <sys/time.h>
  40.  
  41. #include <netinet/in.h>
  42.  
  43. #include <arpa/telnet.h>
  44.  
  45. #include <stdio.h>
  46. #include <signal.h>
  47. #include <errno.h>
  48. #include <sgtty.h>
  49. #include <netdb.h>
  50. #include <syslog.h>
  51. #include <ctype.h>
  52.  
  53. #define    OPT_NO            0        /* won't do this option */
  54. #define    OPT_YES            1        /* will do this option */
  55. #define    OPT_YES_BUT_ALWAYS_LOOK    2
  56. #define    OPT_NO_BUT_ALWAYS_LOOK    3
  57. char    hisopts[256];
  58. char    myopts[256];
  59.  
  60. char    doopt[] = { IAC, DO, '%', 'c', 0 };
  61. char    dont[] = { IAC, DONT, '%', 'c', 0 };
  62. char    will[] = { IAC, WILL, '%', 'c', 0 };
  63. char    wont[] = { IAC, WONT, '%', 'c', 0 };
  64.  
  65. /*
  66.  * I/O data buffers, pointers, and counters.
  67.  */
  68. char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  69.  
  70. char    ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
  71.  
  72. char    netibuf[BUFSIZ], *netip = netibuf;
  73. #define    NIACCUM(c)    {   *netip++ = c; \
  74.                 ncc++; \
  75.             }
  76.  
  77. char    netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
  78. char    *neturg = 0;        /* one past last bye of urgent data */
  79.     /* the remote system seems to NOT be an old 4.2 */
  80. int    not42 = 1;
  81.  
  82.  
  83. char BANNER1[] = "\r\n\r\n4.3 BSD UNIX (",
  84.     BANNER2[] = ")\r\n\r\0\r\n\r\0";
  85.  
  86.         /* buffer for sub-options */
  87. char    subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
  88. #define    SB_CLEAR()    subpointer = subbuffer;
  89. #define    SB_TERM()    { subend = subpointer; SB_CLEAR(); }
  90. #define    SB_ACCUM(c)    if (subpointer < (subbuffer+sizeof subbuffer)) { \
  91.                 *subpointer++ = (c); \
  92.             }
  93. #define    SB_GET()    ((*subpointer++)&0xff)
  94. #define    SB_EOF()    (subpointer >= subend)
  95.  
  96. int    pcc, ncc;
  97.  
  98. int    pty, net;
  99. int    inter;
  100. extern    char **environ;
  101. extern    int errno;
  102. char    *line;
  103. int    SYNCHing = 0;        /* we are in TELNET SYNCH mode */
  104. /*
  105.  * The following are some clocks used to decide how to interpret
  106.  * the relationship between various variables.
  107.  */
  108.  
  109. struct {
  110.     int
  111.     system,            /* what the current time is */
  112.     echotoggle,        /* last time user entered echo character */
  113.     modenegotiated,        /* last time operating mode negotiated */
  114.     didnetreceive,        /* last time we read data from network */
  115.     ttypeopt,        /* ttype will/won't received */
  116.     ttypesubopt,        /* ttype subopt is received */
  117.     getterminal,        /* time started to get terminal information */
  118.     gotDM;            /* when did we last see a data mark */
  119. } clocks;
  120.  
  121. #define    settimer(x)    (clocks.x = ++clocks.system)
  122. #define    sequenceIs(x,y)    (clocks.x < clocks.y)
  123.  
  124. main(argc, argv)
  125.     char *argv[];
  126. {
  127.     struct sockaddr_in from;
  128.     int on = 1, fromlen;
  129.  
  130. #if    defined(DEBUG)
  131.     {
  132.         int s, ns, foo;
  133.         struct servent *sp;
  134.         static struct sockaddr_in sin = { AF_INET };
  135.  
  136.         sp = getservbyname("telnet", "tcp");
  137.         if (sp == 0) {
  138.             fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
  139.             exit(1);
  140.         }
  141.         sin.sin_port = sp->s_port;
  142.         argc--, argv++;
  143.         if (argc > 0) {
  144.             sin.sin_port = atoi(*argv);
  145.             sin.sin_port = htons((u_short)sin.sin_port);
  146.         }
  147.  
  148.         s = socket(AF_INET, SOCK_STREAM, 0);
  149.         if (s < 0) {
  150.             perror("telnetd: socket");;
  151.             exit(1);
  152.         }
  153.         if (bind(s, &sin, sizeof sin) < 0) {
  154.         perror("bind");
  155.         exit(1);
  156.         }
  157.         if (listen(s, 1) < 0) {
  158.         perror("listen");
  159.         exit(1);
  160.         }
  161.         foo = sizeof sin;
  162.         ns = accept(s, &sin, &foo);
  163.         if (ns < 0) {
  164.         perror("accept");
  165.         exit(1);
  166.         }
  167.         dup2(ns, 0);
  168.         close(s);
  169.     }
  170. #endif    /* defined(DEBUG) */
  171.     openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  172.     fromlen = sizeof (from);
  173.     if (getpeername(0, &from, &fromlen) < 0) {
  174.         fprintf(stderr, "%s: ", argv[0]);
  175.         perror("getpeername");
  176.         _exit(1);
  177.     }
  178.     if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
  179.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  180.     }
  181.     doit(0, &from);
  182. }
  183.  
  184. char    *terminaltype = 0;
  185. char    *envinit[2];
  186. int    cleanup();
  187.  
  188. /*
  189.  * ttloop
  190.  *
  191.  *    A small subroutine to flush the network output buffer, get some data
  192.  * from the network, and pass it through the telnet state machine.  We
  193.  * also flush the pty input buffer (by dropping its data) if it becomes
  194.  * too full.
  195.  */
  196.  
  197. void
  198. ttloop()
  199. {
  200.     if (nfrontp-nbackp) {
  201.     netflush();
  202.     }
  203.     ncc = read(net, netibuf, sizeof netibuf);
  204.     if (ncc < 0) {
  205.     syslog(LOG_INFO, "ttloop:  read: %m\n");
  206.     exit(1);
  207.     } else if (ncc == 0) {
  208.     syslog(LOG_INFO, "ttloop:  peer died: %m\n");
  209.     exit(1);
  210.     }
  211.     netip = netibuf;
  212.     telrcv();            /* state machine */
  213.     if (ncc > 0) {
  214.     pfrontp = pbackp = ptyobuf;
  215.     telrcv();
  216.     }
  217. }
  218.  
  219. /*
  220.  * getterminaltype
  221.  *
  222.  *    Ask the other end to send along its terminal type.
  223.  * Output is the variable terminaltype filled in.
  224.  */
  225.  
  226. void
  227. getterminaltype()
  228. {
  229.     static char sbuf[] = { IAC, DO, TELOPT_TTYPE };
  230.  
  231.     settimer(getterminal);
  232.     bcopy(sbuf, nfrontp, sizeof sbuf);
  233.     nfrontp += sizeof sbuf;
  234.     hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK;
  235.     while (sequenceIs(ttypeopt, getterminal)) {
  236.     ttloop();
  237.     }
  238.     if (hisopts[TELOPT_TTYPE] == OPT_YES) {
  239.     static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
  240.  
  241.     bcopy(sbbuf, nfrontp, sizeof sbbuf);
  242.     nfrontp += sizeof sbbuf;
  243.     while (sequenceIs(ttypesubopt, getterminal)) {
  244.         ttloop();
  245.     }
  246.     }
  247. }
  248.  
  249. /*
  250.  * Get a pty, scan input lines.
  251.  */
  252. doit(f, who)
  253.     int f;
  254.     struct sockaddr_in *who;
  255. {
  256.     char *host, *inet_ntoa();
  257.     int i, p, t;
  258.     struct sgttyb b;
  259.     struct hostent *hp;
  260.     int c;
  261.  
  262.     for (c = 'p'; c <= 's'; c++) {
  263.         struct stat stb;
  264.  
  265.         line = "/dev/ptyXX";
  266.         line[strlen("/dev/pty")] = c;
  267.         line[strlen("/dev/ptyp")] = '0';
  268.         if (stat(line, &stb) < 0)
  269.             break;
  270.         for (i = 0; i < 16; i++) {
  271.             line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
  272.             p = open(line, 2);
  273.             if (p > 0)
  274.                 goto gotpty;
  275.         }
  276.     }
  277.     fatal(f, "All network ports in use");
  278.     /*NOTREACHED*/
  279. gotpty:
  280.     dup2(f, 0);
  281.     line[strlen("/dev/")] = 't';
  282.     t = open("/dev/tty", O_RDWR);
  283.     if (t >= 0) {
  284.         ioctl(t, TIOCNOTTY, 0);
  285.         close(t);
  286.     }
  287.     t = open(line, O_RDWR);
  288.     if (t < 0)
  289.         fatalperror(f, line, errno);
  290.     ioctl(t, TIOCGETP, &b);
  291.     b.sg_flags = CRMOD|XTABS|ANYP;
  292.     ioctl(t, TIOCSETP, &b);
  293.     ioctl(p, TIOCGETP, &b);
  294.     b.sg_flags &= ~ECHO;
  295.     ioctl(p, TIOCSETP, &b);
  296.     hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr),
  297.         who->sin_family);
  298.     if (hp)
  299.         host = hp->h_name;
  300.     else
  301.         host = inet_ntoa(who->sin_addr);
  302.  
  303.     net = f;
  304.     pty = p;
  305.  
  306.     /*
  307.      * get terminal type.
  308.      */
  309.     getterminaltype();
  310.  
  311.     if ((i = fork()) < 0)
  312.         fatalperror(f, "fork", errno);
  313.     if (i)
  314.         telnet(f, p);
  315.     close(f);
  316.     close(p);
  317.     dup2(t, 0);
  318.     dup2(t, 1);
  319.     dup2(t, 2);
  320.     close(t);
  321.     envinit[0] = terminaltype;
  322.     envinit[1] = 0;
  323.     environ = envinit;
  324.     /*
  325.      * -h : pass on name of host.
  326.      *        WARNING:  -h is accepted by login if and only if
  327.      *            getuid() == 0.
  328.      * -p : don't clobber the environment (so terminal type stays set).
  329.      */
  330.     execl("/bin/login", "login", "-h", host,
  331.                     terminaltype ? "-p" : 0, 0);
  332.     fatalperror(f, "/bin/login", errno);
  333.     /*NOTREACHED*/
  334. }
  335.  
  336. fatal(f, msg)
  337.     int f;
  338.     char *msg;
  339. {
  340.     char buf[BUFSIZ];
  341.  
  342.     (void) sprintf(buf, "telnetd: %s.\r\n", msg);
  343.     (void) write(f, buf, strlen(buf));
  344.     exit(1);
  345. }
  346.  
  347. fatalperror(f, msg, errno)
  348.     int f;
  349.     char *msg;
  350.     int errno;
  351. {
  352.     char buf[BUFSIZ];
  353.     extern char *sys_errlist[];
  354.  
  355.     (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
  356.     fatal(f, buf);
  357. }
  358.  
  359.  
  360. /*
  361.  * Check a descriptor to see if out of band data exists on it.
  362.  */
  363.  
  364.  
  365. stilloob(s)
  366. int    s;        /* socket number */
  367. {
  368.     static struct timeval timeout = { 0 };
  369.     fd_set    excepts;
  370.     int value;
  371.  
  372.     do {
  373.     FD_ZERO(&excepts);
  374.     FD_SET(s, &excepts);
  375.     value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
  376.     } while ((value == -1) && (errno == EINTR));
  377.  
  378.     if (value < 0) {
  379.     fatalperror(pty, "select", errno);
  380.     }
  381.     if (FD_ISSET(s, &excepts)) {
  382.     return 1;
  383.     } else {
  384.     return 0;
  385.     }
  386. }
  387.  
  388. /*
  389.  * Main loop.  Select from pty and network, and
  390.  * hand data to telnet receiver finite state machine.
  391.  */
  392. telnet(f, p)
  393. {
  394.     int on = 1;
  395.     char hostname[MAXHOSTNAMELEN];
  396.  
  397.     ioctl(f, FIONBIO, &on);
  398.     ioctl(p, FIONBIO, &on);
  399. #if    defined(SO_OOBINLINE)
  400.     setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  401. #endif    /* defined(SO_OOBINLINE) */
  402.     signal(SIGTSTP, SIG_IGN);
  403.     signal(SIGCHLD, cleanup);
  404.     setpgrp(0, 0);
  405.  
  406.     /*
  407.      * Request to do remote echo and to suppress go ahead.
  408.      */
  409.     if (!myopts[TELOPT_ECHO]) {
  410.         dooption(TELOPT_ECHO);
  411.     }
  412.     if (!myopts[TELOPT_SGA]) {
  413.         dooption(TELOPT_SGA);
  414.     }
  415.     /*
  416.      * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
  417.      * because 4.2 clients are unable to deal with TCP urgent data.
  418.      *
  419.      * To find out, we send out a "DO ECHO".  If the remote system
  420.      * answers "WILL ECHO" it is probably a 4.2 client, and we note
  421.      * that fact ("WILL ECHO" ==> that the client will echo what
  422.      * WE, the server, sends it; it does NOT mean that the client will
  423.      * echo the terminal input).
  424.      */
  425.     sprintf(nfrontp, doopt, TELOPT_ECHO);
  426.     nfrontp += sizeof doopt-2;
  427.     hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
  428.  
  429.     /*
  430.      * Show banner that getty never gave.
  431.      *
  432.      * The banner includes some null's (for TELNET CR disambiguation),
  433.      * so we have to be somewhat complicated.
  434.      */
  435.  
  436.     gethostname(hostname, sizeof (hostname));
  437.  
  438.     bcopy(BANNER1, nfrontp, sizeof BANNER1 -1);
  439.     nfrontp += sizeof BANNER1 - 1;
  440.     bcopy(hostname, nfrontp, strlen(hostname));
  441.     nfrontp += strlen(hostname);
  442.     bcopy(BANNER2, nfrontp, sizeof BANNER2 -1);
  443.     nfrontp += sizeof BANNER2 - 1;
  444.  
  445.     /*
  446.      * Call telrcv() once to pick up anything received during
  447.      * terminal type negotiation.
  448.      */
  449.     telrcv();
  450.  
  451.     for (;;) {
  452.         fd_set ibits, obits, xbits;
  453.         register int c;
  454.  
  455.         if (ncc < 0 && pcc < 0)
  456.             break;
  457.  
  458.         FD_ZERO(&ibits);
  459.         FD_ZERO(&obits);
  460.         FD_ZERO(&xbits);
  461.         /*
  462.          * Never look for input if there's still
  463.          * stuff in the corresponding output buffer
  464.          */
  465.         if (nfrontp - nbackp || pcc > 0) {
  466.             FD_SET(f, &obits);
  467.         } else {
  468.             FD_SET(p, &ibits);
  469.         }
  470.         if (pfrontp - pbackp || ncc > 0) {
  471.             FD_SET(p, &obits);
  472.         } else {
  473.             FD_SET(f, &ibits);
  474.         }
  475.         if (!SYNCHing) {
  476.             FD_SET(f, &xbits);
  477.         }
  478.         if ((c = select(16, &ibits, &obits, &xbits,
  479.                         (struct timeval *)0)) < 1) {
  480.             if (c == -1) {
  481.                 if (errno == EINTR) {
  482.                     continue;
  483.                 }
  484.             }
  485.             sleep(5);
  486.             continue;
  487.         }
  488.  
  489.         /*
  490.          * Any urgent data?
  491.          */
  492.         if (FD_ISSET(net, &xbits)) {
  493.             SYNCHing = 1;
  494.         }
  495.  
  496.         /*
  497.          * Something to read from the network...
  498.          */
  499.         if (FD_ISSET(net, &ibits)) {
  500. #if    !defined(SO_OOBINLINE)
  501.             /*
  502.              * In 4.2 (and 4.3 beta) systems, the
  503.              * OOB indication and data handling in the kernel
  504.              * is such that if two separate TCP Urgent requests
  505.              * come in, one byte of TCP data will be overlaid.
  506.              * This is fatal for Telnet, but we try to live
  507.              * with it.
  508.              *
  509.              * In addition, in 4.2 (and...), a special protocol
  510.              * is needed to pick up the TCP Urgent data in
  511.              * the correct sequence.
  512.              *
  513.              * What we do is:  if we think we are in urgent
  514.              * mode, we look to see if we are "at the mark".
  515.              * If we are, we do an OOB receive.  If we run
  516.              * this twice, we will do the OOB receive twice,
  517.              * but the second will fail, since the second
  518.              * time we were "at the mark", but there wasn't
  519.              * any data there (the kernel doesn't reset
  520.              * "at the mark" until we do a normal read).
  521.              * Once we've read the OOB data, we go ahead
  522.              * and do normal reads.
  523.              *
  524.              * There is also another problem, which is that
  525.              * since the OOB byte we read doesn't put us
  526.              * out of OOB state, and since that byte is most
  527.              * likely the TELNET DM (data mark), we would
  528.              * stay in the TELNET SYNCH (SYNCHing) state.
  529.              * So, clocks to the rescue.  If we've "just"
  530.              * received a DM, then we test for the
  531.              * presence of OOB data when the receive OOB
  532.              * fails (and AFTER we did the normal mode read
  533.              * to clear "at the mark").
  534.              */
  535.             if (SYNCHing) {
  536.             int atmark;
  537.  
  538.             ioctl(net, SIOCATMARK, (char *)&atmark);
  539.             if (atmark) {
  540.                 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
  541.                 if ((ncc == -1) && (errno == EINVAL)) {
  542.                 ncc = read(net, netibuf, sizeof (netibuf));
  543.                 if (sequenceIs(didnetreceive, gotDM)) {
  544.                     SYNCHing = stilloob(net);
  545.                 }
  546.                 }
  547.             } else {
  548.                 ncc = read(net, netibuf, sizeof (netibuf));
  549.             }
  550.             } else {
  551.             ncc = read(net, netibuf, sizeof (netibuf));
  552.             }
  553.             settimer(didnetreceive);
  554. #else    /* !defined(SO_OOBINLINE)) */
  555.             ncc = read(net, netibuf, sizeof (netibuf));
  556. #endif    /* !defined(SO_OOBINLINE)) */
  557.             if (ncc < 0 && errno == EWOULDBLOCK)
  558.             ncc = 0;
  559.             else {
  560.             if (ncc <= 0) {
  561.                 break;
  562.             }
  563.             netip = netibuf;
  564.             }
  565.         }
  566.  
  567.         /*
  568.          * Something to read from the pty...
  569.          */
  570.         if (FD_ISSET(p, &ibits)) {
  571.             pcc = read(p, ptyibuf, BUFSIZ);
  572.             if (pcc < 0 && errno == EWOULDBLOCK)
  573.                 pcc = 0;
  574.             else {
  575.                 if (pcc <= 0)
  576.                     break;
  577.                 ptyip = ptyibuf;
  578.             }
  579.         }
  580.  
  581.         while (pcc > 0) {
  582.             if ((&netobuf[BUFSIZ] - nfrontp) < 2)
  583.                 break;
  584.             c = *ptyip++ & 0377, pcc--;
  585.             if (c == IAC)
  586.                 *nfrontp++ = c;
  587.             *nfrontp++ = c;
  588.             /* Don't do CR-NUL if we are in binary mode */
  589.             if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
  590.                 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
  591.                     *nfrontp++ = *ptyip++ & 0377;
  592.                     pcc--;
  593.                 } else
  594.                     *nfrontp++ = '\0';
  595.             }
  596.         }
  597.         if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
  598.             netflush();
  599.         if (ncc > 0)
  600.             telrcv();
  601.         if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
  602.             ptyflush();
  603.     }
  604.     cleanup();
  605. }
  606.     
  607. /*
  608.  * State for recv fsm
  609.  */
  610. #define    TS_DATA        0    /* base state */
  611. #define    TS_IAC        1    /* look for double IAC's */
  612. #define    TS_CR        2    /* CR-LF ->'s CR */
  613. #define    TS_SB        3    /* throw away begin's... */
  614. #define    TS_SE        4    /* ...end's (suboption negotiation) */
  615. #define    TS_WILL        5    /* will option negotiation */
  616. #define    TS_WONT        6    /* wont " */
  617. #define    TS_DO        7    /* do " */
  618. #define    TS_DONT        8    /* dont " */
  619.  
  620. telrcv()
  621. {
  622.     register int c;
  623.     static int state = TS_DATA;
  624.  
  625.     while (ncc > 0) {
  626.         if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  627.             return;
  628.         c = *netip++ & 0377, ncc--;
  629.         switch (state) {
  630.  
  631.         case TS_CR:
  632.             state = TS_DATA;
  633.             /* Strip off \n or \0 after a \r */
  634.             if ((c == 0) || (c == '\n')) {
  635.                 break;
  636.             }
  637.             /* FALL THROUGH */
  638.  
  639.         case TS_DATA:
  640.             if (c == IAC) {
  641.                 state = TS_IAC;
  642.                 break;
  643.             }
  644.             if (inter > 0)
  645.                 break;
  646.             /*
  647.              * We now map \r\n ==> \r for pragmatic reasons.
  648.              * Many client implementations send \r\n when
  649.              * the user hits the CarriageReturn key.
  650.              * 
  651.              * We USED to map \r\n ==> \n, since \r\n says
  652.              * that we want to be in column 1 of the next
  653.              * printable line, and \n is the standard
  654.              * unix way of saying that (\r is only good
  655.              * if CRMOD is set, which it normally is).
  656.              */
  657.             if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
  658.                 state = TS_CR;
  659.             }
  660.             *pfrontp++ = c;
  661.             break;
  662.  
  663.         case TS_IAC:
  664.             switch (c) {
  665.  
  666.             /*
  667.              * Send the process on the pty side an
  668.              * interrupt.  Do this with a NULL or
  669.              * interrupt char; depending on the tty mode.
  670.              */
  671.             case IP:
  672.                 interrupt();
  673.                 break;
  674.  
  675.             case BREAK:
  676.                 sendbrk();
  677.                 break;
  678.  
  679.             /*
  680.              * Are You There?
  681.              */
  682.             case AYT:
  683.                 strcpy(nfrontp, "\r\n[Yes]\r\n");
  684.                 nfrontp += 9;
  685.                 break;
  686.  
  687.             /*
  688.              * Abort Output
  689.              */
  690.             case AO: {
  691.                     struct ltchars tmpltc;
  692.  
  693.                     ptyflush();    /* half-hearted */
  694.                     ioctl(pty, TIOCGLTC, &tmpltc);
  695.                     if (tmpltc.t_flushc != '\377') {
  696.                         *pfrontp++ = tmpltc.t_flushc;
  697.                     }
  698.                     netclear();    /* clear buffer back */
  699.                     *nfrontp++ = IAC;
  700.                     *nfrontp++ = DM;
  701.                     neturg = nfrontp-1; /* off by one XXX */
  702.                     break;
  703.                 }
  704.  
  705.             /*
  706.              * Erase Character and
  707.              * Erase Line
  708.              */
  709.             case EC:
  710.             case EL: {
  711.                     struct sgttyb b;
  712.                     char ch;
  713.  
  714.                     ptyflush();    /* half-hearted */
  715.                     ioctl(pty, TIOCGETP, &b);
  716.                     ch = (c == EC) ?
  717.                         b.sg_erase : b.sg_kill;
  718.                     if (ch != '\377') {
  719.                         *pfrontp++ = ch;
  720.                     }
  721.                     break;
  722.                 }
  723.  
  724.             /*
  725.              * Check for urgent data...
  726.              */
  727.             case DM:
  728.                 SYNCHing = stilloob(net);
  729.                 settimer(gotDM);
  730.                 break;
  731.  
  732.  
  733.             /*
  734.              * Begin option subnegotiation...
  735.              */
  736.             case SB:
  737.                 state = TS_SB;
  738.                 continue;
  739.  
  740.             case WILL:
  741.                 state = TS_WILL;
  742.                 continue;
  743.  
  744.             case WONT:
  745.                 state = TS_WONT;
  746.                 continue;
  747.  
  748.             case DO:
  749.                 state = TS_DO;
  750.                 continue;
  751.  
  752.             case DONT:
  753.                 state = TS_DONT;
  754.                 continue;
  755.  
  756.             case IAC:
  757.                 *pfrontp++ = c;
  758.                 break;
  759.             }
  760.             state = TS_DATA;
  761.             break;
  762.  
  763.         case TS_SB:
  764.             if (c == IAC) {
  765.                 state = TS_SE;
  766.             } else {
  767.                 SB_ACCUM(c);
  768.             }
  769.             break;
  770.  
  771.         case TS_SE:
  772.             if (c != SE) {
  773.                 if (c != IAC) {
  774.                     SB_ACCUM(IAC);
  775.                 }
  776.                 SB_ACCUM(c);
  777.                 state = TS_SB;
  778.             } else {
  779.                 SB_TERM();
  780.                 suboption();    /* handle sub-option */
  781.                 state = TS_DATA;
  782.             }
  783.             break;
  784.  
  785.         case TS_WILL:
  786.             if (hisopts[c] != OPT_YES)
  787.                 willoption(c);
  788.             state = TS_DATA;
  789.             continue;
  790.  
  791.         case TS_WONT:
  792.             if (hisopts[c] != OPT_NO)
  793.                 wontoption(c);
  794.             state = TS_DATA;
  795.             continue;
  796.  
  797.         case TS_DO:
  798.             if (myopts[c] != OPT_YES)
  799.                 dooption(c);
  800.             state = TS_DATA;
  801.             continue;
  802.  
  803.         case TS_DONT:
  804.             if (myopts[c] != OPT_NO) {
  805.                 dontoption(c);
  806.             }
  807.             state = TS_DATA;
  808.             continue;
  809.  
  810.         default:
  811.             syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
  812.             printf("telnetd: panic state=%d\n", state);
  813.             exit(1);
  814.         }
  815.     }
  816. }
  817.  
  818. willoption(option)
  819.     int option;
  820. {
  821.     char *fmt;
  822.  
  823.     switch (option) {
  824.  
  825.     case TELOPT_BINARY:
  826.         mode(RAW, 0);
  827.         fmt = doopt;
  828.         break;
  829.  
  830.     case TELOPT_ECHO:
  831.         not42 = 0;        /* looks like a 4.2 system */
  832.         /*
  833.          * Now, in a 4.2 system, to break them out of ECHOing
  834.          * (to the terminal) mode, we need to send a "WILL ECHO".
  835.          * Kludge upon kludge!
  836.          */
  837.         if (myopts[TELOPT_ECHO] == OPT_YES) {
  838.             dooption(TELOPT_ECHO);
  839.         }
  840.         fmt = dont;
  841.         break;
  842.  
  843.     case TELOPT_TTYPE:
  844.         settimer(ttypeopt);
  845.         if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
  846.             hisopts[TELOPT_TTYPE] = OPT_YES;
  847.             return;
  848.         }
  849.         fmt = doopt;
  850.         break;
  851.  
  852.     case TELOPT_SGA:
  853.         fmt = doopt;
  854.         break;
  855.  
  856.     case TELOPT_TM:
  857.         fmt = dont;
  858.         break;
  859.  
  860.     default:
  861.         fmt = dont;
  862.         break;
  863.     }
  864.     if (fmt == doopt) {
  865.         hisopts[option] = OPT_YES;
  866.     } else {
  867.         hisopts[option] = OPT_NO;
  868.     }
  869.     sprintf(nfrontp, fmt, option);
  870.     nfrontp += sizeof (dont) - 2;
  871. }
  872.  
  873. wontoption(option)
  874.     int option;
  875. {
  876.     char *fmt;
  877.  
  878.     switch (option) {
  879.     case TELOPT_ECHO:
  880.         not42 = 1;        /* doesn't seem to be a 4.2 system */
  881.         break;
  882.  
  883.     case TELOPT_BINARY:
  884.         mode(0, RAW);
  885.         break;
  886.  
  887.     case TELOPT_TTYPE:
  888.         settimer(ttypeopt);
  889.         break;
  890.     }
  891.  
  892.     fmt = dont;
  893.     hisopts[option] = OPT_NO;
  894.     sprintf(nfrontp, fmt, option);
  895.     nfrontp += sizeof (doopt) - 2;
  896. }
  897.  
  898. dooption(option)
  899.     int option;
  900. {
  901.     char *fmt;
  902.  
  903.     switch (option) {
  904.  
  905.     case TELOPT_TM:
  906.         fmt = wont;
  907.         break;
  908.  
  909.     case TELOPT_ECHO:
  910.         mode(ECHO|CRMOD, 0);
  911.         fmt = will;
  912.         break;
  913.  
  914.     case TELOPT_BINARY:
  915.         mode(RAW, 0);
  916.         fmt = will;
  917.         break;
  918.  
  919.     case TELOPT_SGA:
  920.         fmt = will;
  921.         break;
  922.  
  923.     default:
  924.         fmt = wont;
  925.         break;
  926.     }
  927.     if (fmt == will) {
  928.         myopts[option] = OPT_YES;
  929.     } else {
  930.         myopts[option] = OPT_NO;
  931.     }
  932.     sprintf(nfrontp, fmt, option);
  933.     nfrontp += sizeof (doopt) - 2;
  934. }
  935.  
  936.  
  937. dontoption(option)
  938. int option;
  939. {
  940.     char *fmt;
  941.  
  942.     switch (option) {
  943.     case TELOPT_ECHO:        /* we should stop echoing */
  944.     mode(0, ECHO|CRMOD);
  945.     fmt = wont;
  946.     break;
  947.  
  948.     default:
  949.     fmt = wont;
  950.     break;
  951.     }
  952.  
  953.     if (fmt = wont) {
  954.     myopts[option] = OPT_NO;
  955.     } else {
  956.     myopts[option] = OPT_YES;
  957.     }
  958.     sprintf(nfrontp, fmt, option);
  959.     nfrontp += sizeof (wont) - 2;
  960. }
  961.  
  962. /*
  963.  * suboption()
  964.  *
  965.  *    Look at the sub-option buffer, and try to be helpful to the other
  966.  * side.
  967.  *
  968.  *    Currently we recognize:
  969.  *
  970.  *    Terminal type is
  971.  */
  972.  
  973. suboption()
  974. {
  975.     switch (SB_GET()) {
  976.     case TELOPT_TTYPE: {        /* Yaaaay! */
  977.     static char terminalname[5+41] = "TERM=";
  978.  
  979.     settimer(ttypesubopt);
  980.  
  981.     if (SB_GET() != TELQUAL_IS) {
  982.         return;        /* ??? XXX but, this is the most robust */
  983.     }
  984.  
  985.     terminaltype = terminalname+strlen(terminalname);
  986.  
  987.     while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
  988.                                     !SB_EOF()) {
  989.         register int c;
  990.  
  991.         c = SB_GET();
  992.         if (isupper(c)) {
  993.         c = tolower(c);
  994.         }
  995.         *terminaltype++ = c;    /* accumulate name */
  996.     }
  997.     *terminaltype = 0;
  998.     terminaltype = terminalname;
  999.     break;
  1000.     }
  1001.  
  1002.     default:
  1003.     ;
  1004.     }
  1005. }
  1006.  
  1007. mode(on, off)
  1008.     int on, off;
  1009. {
  1010.     struct sgttyb b;
  1011.  
  1012.     ptyflush();
  1013.     ioctl(pty, TIOCGETP, &b);
  1014.     b.sg_flags |= on;
  1015.     b.sg_flags &= ~off;
  1016.     ioctl(pty, TIOCSETP, &b);
  1017. }
  1018.  
  1019. /*
  1020.  * Send interrupt to process on other side of pty.
  1021.  * If it is in raw mode, just write NULL;
  1022.  * otherwise, write intr char.
  1023.  */
  1024. interrupt()
  1025. {
  1026.     struct sgttyb b;
  1027.     struct tchars tchars;
  1028.  
  1029.     ptyflush();    /* half-hearted */
  1030.     ioctl(pty, TIOCGETP, &b);
  1031.     if (b.sg_flags & RAW) {
  1032.         *pfrontp++ = '\0';
  1033.         return;
  1034.     }
  1035.     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
  1036.         '\177' : tchars.t_intrc;
  1037. }
  1038.  
  1039. /*
  1040.  * Send quit to process on other side of pty.
  1041.  * If it is in raw mode, just write NULL;
  1042.  * otherwise, write quit char.
  1043.  */
  1044. sendbrk()
  1045. {
  1046.     struct sgttyb b;
  1047.     struct tchars tchars;
  1048.  
  1049.     ptyflush();    /* half-hearted */
  1050.     ioctl(pty, TIOCGETP, &b);
  1051.     if (b.sg_flags & RAW) {
  1052.         *pfrontp++ = '\0';
  1053.         return;
  1054.     }
  1055.     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
  1056.         '\034' : tchars.t_quitc;
  1057. }
  1058.  
  1059. ptyflush()
  1060. {
  1061.     int n;
  1062.  
  1063.     if ((n = pfrontp - pbackp) > 0)
  1064.         n = write(pty, pbackp, n);
  1065.     if (n < 0)
  1066.         return;
  1067.     pbackp += n;
  1068.     if (pbackp == pfrontp)
  1069.         pbackp = pfrontp = ptyobuf;
  1070. }
  1071.  
  1072. /*
  1073.  * nextitem()
  1074.  *
  1075.  *    Return the address of the next "item" in the TELNET data
  1076.  * stream.  This will be the address of the next character if
  1077.  * the current address is a user data character, or it will
  1078.  * be the address of the character following the TELNET command
  1079.  * if the current address is a TELNET IAC ("I Am a Command")
  1080.  * character.
  1081.  */
  1082.  
  1083. char *
  1084. nextitem(current)
  1085. char    *current;
  1086. {
  1087.     if ((*current&0xff) != IAC) {
  1088.     return current+1;
  1089.     }
  1090.     switch (*(current+1)&0xff) {
  1091.     case DO:
  1092.     case DONT:
  1093.     case WILL:
  1094.     case WONT:
  1095.     return current+3;
  1096.     case SB:        /* loop forever looking for the SE */
  1097.     {
  1098.         register char *look = current+2;
  1099.  
  1100.         for (;;) {
  1101.         if ((*look++&0xff) == IAC) {
  1102.             if ((*look++&0xff) == SE) {
  1103.             return look;
  1104.             }
  1105.         }
  1106.         }
  1107.     }
  1108.     default:
  1109.     return current+2;
  1110.     }
  1111. }
  1112.  
  1113.  
  1114. /*
  1115.  * netclear()
  1116.  *
  1117.  *    We are about to do a TELNET SYNCH operation.  Clear
  1118.  * the path to the network.
  1119.  *
  1120.  *    Things are a bit tricky since we may have sent the first
  1121.  * byte or so of a previous TELNET command into the network.
  1122.  * So, we have to scan the network buffer from the beginning
  1123.  * until we are up to where we want to be.
  1124.  *
  1125.  *    A side effect of what we do, just to keep things
  1126.  * simple, is to clear the urgent data pointer.  The principal
  1127.  * caller should be setting the urgent data pointer AFTER calling
  1128.  * us in any case.
  1129.  */
  1130.  
  1131. netclear()
  1132. {
  1133.     register char *thisitem, *next;
  1134.     char *good;
  1135. #define    wewant(p)    ((nfrontp > p) && ((*p&0xff) == IAC) && \
  1136.                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
  1137.  
  1138.     thisitem = netobuf;
  1139.  
  1140.     while ((next = nextitem(thisitem)) <= nbackp) {
  1141.     thisitem = next;
  1142.     }
  1143.  
  1144.     /* Now, thisitem is first before/at boundary. */
  1145.  
  1146.     good = netobuf;    /* where the good bytes go */
  1147.  
  1148.     while (nfrontp > thisitem) {
  1149.     if (wewant(thisitem)) {
  1150.         int length;
  1151.  
  1152.         next = thisitem;
  1153.         do {
  1154.         next = nextitem(next);
  1155.         } while (wewant(next) && (nfrontp > next));
  1156.         length = next-thisitem;
  1157.         bcopy(thisitem, good, length);
  1158.         good += length;
  1159.         thisitem = next;
  1160.     } else {
  1161.         thisitem = nextitem(thisitem);
  1162.     }
  1163.     }
  1164.  
  1165.     nbackp = netobuf;
  1166.     nfrontp = good;        /* next byte to be sent */
  1167.     neturg = 0;
  1168. }
  1169.  
  1170. /*
  1171.  *  netflush
  1172.  *        Send as much data as possible to the network,
  1173.  *    handling requests for urgent data.
  1174.  */
  1175.  
  1176.  
  1177. netflush()
  1178. {
  1179.     int n;
  1180.  
  1181.     if ((n = nfrontp - nbackp) > 0) {
  1182.     /*
  1183.      * if no urgent data, or if the other side appears to be an
  1184.      * old 4.2 client (and thus unable to survive TCP urgent data),
  1185.      * write the entire buffer in non-OOB mode.
  1186.      */
  1187.     if ((neturg == 0) || (not42 == 0)) {
  1188.         n = write(net, nbackp, n);    /* normal write */
  1189.     } else {
  1190.         n = neturg - nbackp;
  1191.         /*
  1192.          * In 4.2 (and 4.3) systems, there is some question about
  1193.          * what byte in a sendOOB operation is the "OOB" data.
  1194.          * To make ourselves compatible, we only send ONE byte
  1195.          * out of band, the one WE THINK should be OOB (though
  1196.          * we really have more the TCP philosophy of urgent data
  1197.          * rather than the Unix philosophy of OOB data).
  1198.          */
  1199.         if (n > 1) {
  1200.         n = send(net, nbackp, n-1, 0);    /* send URGENT all by itself */
  1201.         } else {
  1202.         n = send(net, nbackp, n, MSG_OOB);    /* URGENT data */
  1203.         }
  1204.     }
  1205.     }
  1206.     if (n < 0) {
  1207.     if (errno == EWOULDBLOCK)
  1208.         return;
  1209.     /* should blow this guy away... */
  1210.     return;
  1211.     }
  1212.     nbackp += n;
  1213.     if (nbackp >= neturg) {
  1214.     neturg = 0;
  1215.     }
  1216.     if (nbackp == nfrontp) {
  1217.     nbackp = nfrontp = netobuf;
  1218.     }
  1219. }
  1220.  
  1221. cleanup()
  1222. {
  1223.  
  1224.     rmut();
  1225.     vhangup();    /* XXX */
  1226.     shutdown(net, 2);
  1227.     exit(1);
  1228. }
  1229.  
  1230. #include <utmp.h>
  1231.  
  1232. struct    utmp wtmp;
  1233. char    wtmpf[]    = "/usr/adm/wtmp";
  1234. char    utmpf[] = "/etc/utmp";
  1235. #define SCPYN(a, b)    strncpy(a, b, sizeof(a))
  1236. #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
  1237.  
  1238. rmut()
  1239. {
  1240.     register f;
  1241.     int found = 0;
  1242.     struct utmp *u, *utmp;
  1243.     int nutmp;
  1244.     struct stat statbf;
  1245.  
  1246.     f = open(utmpf, O_RDWR);
  1247.     if (f >= 0) {
  1248.         fstat(f, &statbf);
  1249.         utmp = (struct utmp *)malloc(statbf.st_size);
  1250.         if (!utmp)
  1251.             syslog(LOG_ERR, "utmp malloc failed");
  1252.         if (statbf.st_size && utmp) {
  1253.             nutmp = read(f, utmp, statbf.st_size);
  1254.             nutmp /= sizeof(struct utmp);
  1255.         
  1256.             for (u = utmp ; u < &utmp[nutmp] ; u++) {
  1257.                 if (SCMPN(u->ut_line, line+5) ||
  1258.                     u->ut_name[0]==0)
  1259.                     continue;
  1260.                 lseek(f, ((long)u)-((long)utmp), L_SET);
  1261.                 SCPYN(u->ut_name, "");
  1262.                 SCPYN(u->ut_host, "");
  1263.                 time(&u->ut_time);
  1264.                 write(f, (char *)u, sizeof(wtmp));
  1265.                 found++;
  1266.             }
  1267.         }
  1268.         close(f);
  1269.     }
  1270.     if (found) {
  1271.         f = open(wtmpf, O_WRONLY|O_APPEND);
  1272.         if (f >= 0) {
  1273.             SCPYN(wtmp.ut_line, line+5);
  1274.             SCPYN(wtmp.ut_name, "");
  1275.             SCPYN(wtmp.ut_host, "");
  1276.             time(&wtmp.ut_time);
  1277.             write(f, (char *)&wtmp, sizeof(wtmp));
  1278.             close(f);
  1279.         }
  1280.     }
  1281.     chmod(line, 0666);
  1282.     chown(line, 0, 0);
  1283.     line[strlen("/dev/")] = 'p';
  1284.     chmod(line, 0666);
  1285.     chown(line, 0, 0);
  1286. }
  1287.